#pragma once

#include <vector>
#include <string>

// utf32 string
class  C32String
{
protected:
    std::vector<char32_t> Data;
public:
    C32String();
    ~C32String() {};

    C32String(const char8_t* InUtf8String);

    C32String(const char32_t* InUtf32String);

    C32String(char32_t InUtf32Char);

    C32String(int64_t InNum);

    C32String(uint64_t InNum); 

    C32String(double InNum, int32_t Precision = 6 ) ;

    C32String(bool InValue);

    C32String(const C32String& Other);

    C32String(const C32String&& Other);

    C32String& operator =(const C32String& Other);

    C32String& operator =(const C32String&& Other);
    
    int64_t ToInt64() const;

    uint64_t ToUInt64() const;

    double ToDouble() const;

    bool ToBool() const;

    bool operator ==(const C32String& Other) const;

    bool operator !=(const C32String& Other) const;

    //for std::map
    bool operator <(const C32String& Other) const;

    uint64_t GetHashCode() const;

    //number of characters
    uint64_t GetLength() const;

    //pre-allocated memory for characters
    //if the current capacity is less than InCharCount, the capacity will be increased to InCharCount
    void Reserve(uint64_t InCharCount);

    const char32_t* GetData() const;

    std::vector<char32_t> GetUnicodes() const;


    C32String operator +(const C32String& Other) const;

    C32String& operator +=(const C32String& Other);

    C32String& operator +=(char32_t Other);

    char32_t operator [](uint64_t Index) const;
    
    bool IsEmpty() const;

    void Clear();

    bool StartsWith(const C32String& Other) const;

    bool EndsWith(const C32String& Other) const;

    C32String SubString(uint64_t StartIndex, uint64_t Length) const;

    C32String SubString(uint64_t StartIndex) const;

    C32String Left(uint64_t Length) const;

    C32String Right(uint64_t Length) const;

    //return the index of the first character of the first occurrence of Other in this string
    //return -1 if not found
    uint64_t Find(const C32String& Other, uint64_t StartIndex = 0) const;

    //return the index of the first character of the last occurrence of Other in this string
    //return -1 if not found
    uint64_t FindLast(const C32String& Other) const;

    //return the index of the first character of the first occurrence of Other in this string
    //return -1 if not found
    uint64_t Find(char32_t Other, uint64_t StartIndex = 0) const;

    //return the index of the first character of the last occurrence of Other in this string
    //return -1 if not found
    uint64_t FindLast(char32_t Other) const;

    C32String ToLower() const;

    C32String ToUpper() const;

    std::vector<C32String> Split(const C32String& Delimiter) const;

    std::vector<C32String> Split(char32_t Delimiter) const;

    //remove blank space at the beginning and the end of the string
    C32String Trim() const;

    C32String Replace(const C32String& From, const C32String& To) const;

    C32String Replace(char32_t From, char32_t To) const;

    //remove all occurrences of the character
    C32String Remove(char32_t Char) const;

    //remove the character at the index
    C32String RemoveAt(uint64_t Index, uint64_t Length = 1) const;

    //remove all occurrences of the string
    C32String Remove(const C32String& Str) const;

    //format string ,for example C32String::Format(U"{} + {} = {}", 1, 2, 3) will return U"1 + 2 = 3"
    template<typename FirstArgType,  typename... Args>
    static C32String Format(const C32String& Format,FirstArgType FirstArg, Args... LeftArgs)
    {
        C32String Result = Format;
        uint64_t Index = Result.Find(U"{}");
        if(Index != -1)
        {
            Result = Result.SubString(0, Index) + C32String(FirstArg) + Result.SubString(Index + 2);
        }

        return Format(Result, LeftArgs...);
    }

    static C32String Format(const C32String& Format)
    {
        return Format;
    }

    static std::vector<char32_t> ToUtf32(const char8_t* InUtf8String);


    //for save to file / send to network / print to console
    //for console out example ,
    std::u8string ToUtf8() const ;

    friend  C32String operator + (const char32_t* Left, const C32String& Right);
    friend  C32String operator + (char32_t Left, const C32String& Right);
};


C32String operator + (const char32_t* Left, const C32String& Right);

C32String operator + (char32_t Left, const C32String& Right);
